/*
 * SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 * Description   : udk ether device interface
 */

#ifndef UDK_ETHDEV_H
#define UDK_ETHDEV_H

#include "udk_common.h"
#include "udk_vdev.h"
#include "udk_mbuf.h"
#include "udk_mempool.h"

#ifdef __cplusplus
extern "C" {
#endif

#define UDK_ETHER_ADDR_LEN  6 /* Length of Ethernet address. */
#define UDK_ETHDEV_QUEUE_STAT_CNTRS 128
#define UDK_MAX_ETHPORTS         32
#define UDK_MAX_QUEUES_PER_PORT  1024
#define UDK_ETH_XSTATS_NAME_SIZE 64
#define UDK_ETH_DEV_NO_OWNER 0

#define UDK_ETH_DEV_FALLBACK_RX_RINGSIZE 512
#define UDK_ETH_DEV_FALLBACK_TX_RINGSIZE 512
#define UDK_ETH_DEV_FALLBACK_RX_NBQUEUES 1
#define UDK_ETH_DEV_FALLBACK_TX_NBQUEUES 1

#define UDK_ETH_DEV_RX_OFFLOAD_VLAN_STRIP  0x00000001
#define UDK_ETH_DEV_RX_OFFLOAD_IPV4_CKSUM  0x00000002
#define UDK_ETH_DEV_RX_OFFLOAD_UDP_CKSUM   0x00000004
#define UDK_ETH_DEV_RX_OFFLOAD_TCP_CKSUM   0x00000008
#define UDK_ETH_DEV_RX_OFFLOAD_JUMBO_FRAME  0x00000800

#define UDK_ETH_DEV_TX_OFFLOAD_VLAN_INSERT 0x00000001
#define UDK_ETH_DEV_TX_OFFLOAD_IPV4_CKSUM  0x00000002
#define UDK_ETH_DEV_TX_OFFLOAD_UDP_CKSUM   0x00000004
#define UDK_ETH_DEV_TX_OFFLOAD_TCP_CKSUM   0x00000008
#define UDK_ETH_DEV_TX_OFFLOAD_TCP_TSO     0x00000020
#define UDK_ETH_DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM 0x00000080 /* Used for tunneling packet. */

#define UDK_ETH_QUEUE_STATE_STOPPED 0
#define UDK_ETH_QUEUE_STATE_STARTED 1

#define MZ_UDK_ETH_DEV_DATA "udk_eth_dev_data"

enum udk_eth_dev_state {
    UDK_ETH_DEV_UNUSED = 0,
    UDK_ETH_DEV_ATTACHED,
    UDK_ETH_DEV_REMOVED,
};

#define UDK_ETHDEV_LOG(level, ...) \
    UDK_LOG(level, ETHDEV, "" __VA_ARGS__)

#define UDK_FUNC_PTR_OR_ERR_RET(func, retval) do { \
    if ((func) == NULL) { \
        return retval; \
    } \
} while (0)

#define UDK_FUNC_PTR_OR_RET(func) do { \
    if ((func) == NULL) { \
        return; \
    } \
} while (0)

/* Retrieve input packets from a receive queue of an Ethernet device. */
typedef uint16_t (*udk_eth_rx_burst_t)(void *rxq, struct udk_mbuf **rx_pkts, uint16_t nb_pkts);

/* Send output packets on a transmit queue of an Ethernet device. */
typedef uint16_t (*udk_eth_tx_burst_t)(void *txq, struct udk_mbuf **tx_pkts, uint16_t nb_pkts);

/* link-level information of an Ethernet port. */
__extension__
struct udk_eth_link {
    uint32_t link_speed;        /* ETH_SPEED_NUM_ */
    uint16_t link_duplex  : 1;  /* ETH_LINK_[HALF/FULL]_DUPLEX */
    uint16_t link_autoneg : 1;  /* ETH_LINK_[AUTONEG/FIXED] */
    uint16_t link_status  : 1;  /* ETH_LINK_[DOWN/UP] */
} __attribute__((aligned(8)));  /* aligned for atomic64 read/write */

/* speeds bitmap flags */
#define ETH_LINK_SPEED_AUTONEG  (0 <<  0)  /* Autonegotiate (all speeds) */
#define ETH_LINK_SPEED_FIXED    (1 <<  0)  /* Disable autoneg (fixed speed) */
#define ETH_LINK_SPEED_10M_HD   (1 <<  1)  /*  10 Mbps half-duplex */
#define ETH_LINK_SPEED_10M      (1 <<  2)  /*  10 Mbps full-duplex */
#define ETH_LINK_SPEED_100M_HD  (1 <<  3)  /* 100 Mbps half-duplex */
#define ETH_LINK_SPEED_100M     (1 <<  4)  /* 100 Mbps full-duplex */
#define ETH_LINK_SPEED_1G       (1 <<  5)  /*   1 Gbps */
#define ETH_LINK_SPEED_2_5G     (1 <<  6)  /* 2.5 Gbps */
#define ETH_LINK_SPEED_5G       (1 <<  7)  /*   5 Gbps */
#define ETH_LINK_SPEED_10G      (1 <<  8)  /*  10 Gbps */
#define ETH_LINK_SPEED_20G      (1 <<  9)  /*  20 Gbps */
#define ETH_LINK_SPEED_25G      (1 << 10)  /*  25 Gbps */
#define ETH_LINK_SPEED_40G      (1 << 11)  /*  40 Gbps */
#define ETH_LINK_SPEED_50G      (1 << 12)  /*  50 Gbps */
#define ETH_LINK_SPEED_56G      (1 << 13)  /*  56 Gbps */
#define ETH_LINK_SPEED_100G     (1 << 14)  /* 100 Gbps */

#define ETH_LINK_HALF_DUPLEX 0 /* Half-duplex connection (see link_duplex). */
#define ETH_LINK_FULL_DUPLEX 1 /* Full-duplex connection (see link_duplex). */
#define ETH_LINK_DOWN        0 /* Link is down (see link_status). */
#define ETH_LINK_UP          1 /* Link is up (see link_status). */
#define ETH_LINK_FIXED       0 /* No autonegotiation (see link_autoneg). */
#define ETH_LINK_AUTONEG     1 /* Autonegotiated (see link_autoneg). */

#define ETH_SPEED_NUM_NONE         0 /* Not defined */
#define ETH_SPEED_NUM_10M         10 /*  10 Mbps */
#define ETH_SPEED_NUM_100M       100 /* 100 Mbps */
#define ETH_SPEED_NUM_1G        1000 /*   1 Gbps */
#define ETH_SPEED_NUM_2_5G      2500 /* 2.5 Gbps */
#define ETH_SPEED_NUM_5G        5000 /*   5 Gbps */
#define ETH_SPEED_NUM_10G      10000 /*  10 Gbps */
#define ETH_SPEED_NUM_20G      20000 /*  20 Gbps */
#define ETH_SPEED_NUM_25G      25000 /*  25 Gbps */
#define ETH_SPEED_NUM_40G      40000 /*  40 Gbps */
#define ETH_SPEED_NUM_50G      50000 /*  50 Gbps */
#define ETH_SPEED_NUM_56G      56000 /*  56 Gbps */
#define ETH_SPEED_NUM_100G    100000 /* 100 Gbps */
#define ETH_SPEED_NUM_200G    200000 /* 200 Gbps */

struct udk_eth_rxmode {
    uint32_t max_rx_pkt_len;  /* Only used if JUMBO_FRAME enabled. */
    uint64_t offloads;

    uint64_t reserved_64s[2]; /* Reserved for future fields */
    void *reserved_ptrs[2];   /* Reserved for future fields */
};

/* configure the TX features of an Ethernet port. */
struct udk_eth_txmode {
    uint64_t offloads;

    uint64_t reserved_64s[2]; /* Reserved for future fields */
    void *reserved_ptrs[2];   /* Reserved for future fields */
};

/* configure an Ethernet port. */
struct udk_eth_conf {
    uint32_t link_speeds;
    struct udk_eth_rxmode rxmode; /* Port RX configuration. */
    struct udk_eth_txmode txmode; /* Port TX configuration. */
};

/*
 * @internal
 * The data part, with no function pointers, associated with each ethernet device.
 *
 * This structure is safe to place in shared memory to be common among different
 * processes in a multi-process configuration.
 */
struct udk_eth_dev_data {
    char name[UDK_DEV_NAME_MAX_LEN]; /* Unique identifier name */

    void **rx_queues; /* Array of pointers to RX queues. */
    void **tx_queues; /* Array of pointers to TX queues. */
    uint16_t nb_rx_queues; /* Number of RX queues. */
    uint16_t nb_tx_queues; /* Number of TX queues. */

    void *dev_private;  /* PMD-specific private data. */

    struct udk_eth_link dev_link;   /* Link-level information & status. */
    struct udk_eth_conf dev_conf;   /* Configuration applied to device. */
    uint16_t mtu;                   /* Maximum Transmission Unit. */
    uint32_t min_rx_buf_size;       /* Common RX buffer size handled by all queues. */

    uint64_t rx_mbuf_alloc_failed; /* RX ring mbuf allocation failures. */
    struct udk_ether_addr *mac_addrs; /* Device Ethernet link address. */
    uint16_t port_id;           /* Device [external] port identifier. */

    __extension__
    uint8_t dev_started : 1;   /* Device state: STARTED(1) / STOPPED(0). */

    uint8_t rx_queue_state[UDK_MAX_QUEUES_PER_PORT]; /* Queues state: STARTED(1) / STOPPED(0). */
    uint8_t tx_queue_state[UDK_MAX_QUEUES_PER_PORT]; /* Queues state: STARTED(1) / STOPPED(0). */
    uint32_t dev_flags;             /* Capabilities. */
    int numa_node;                  /* NUMA node connection. */

    uint64_t reserved_64s[4]; /* Reserved for future fields */
    void *reserved_ptrs[4];   /* Reserved for future fields */
} udk_cache_aligned;

struct udk_eth_stats {
    uint64_t ipackets;  /* Total number of successfully received packets. */
    uint64_t opackets;  /* Total number of successfully transmitted packets. */
    uint64_t ibytes;    /* Total number of successfully received bytes. */
    uint64_t obytes;    /* Total number of successfully transmitted bytes. */
    uint64_t imissed;   /* Total of RX packets dropped by the HW. */
    uint64_t ierrors;   /* Total number of erroneous received packets. */
    uint64_t oerrors;   /* Total number of failed transmitted packets. */
    uint64_t rx_nombuf; /* Total number of RX mbuf allocation failures. */
    uint64_t q_ipackets[UDK_ETHDEV_QUEUE_STAT_CNTRS];  /* Total number of queue RX packets. */
    uint64_t q_opackets[UDK_ETHDEV_QUEUE_STAT_CNTRS];  /* Total number of queue TX packets. */
    uint64_t q_ibytes[UDK_ETHDEV_QUEUE_STAT_CNTRS]; /* Total number of successfully received queue bytes. */
    uint64_t q_obytes[UDK_ETHDEV_QUEUE_STAT_CNTRS]; /* Total number of successfully transmitted queue bytes. */
    uint64_t q_errors[UDK_ETHDEV_QUEUE_STAT_CNTRS]; /* Total number of queue packets received that are dropped. */
};

struct udk_eth_xstat_name {
    char name[UDK_ETH_XSTATS_NAME_SIZE]; /* The statistic name. */
};

struct udk_eth_rxconf {
    uint64_t offloads;

    uint64_t reserved_64s[2]; /* Reserved for future fields */
    void *reserved_ptrs[2];   /* Reserved for future fields */
};

struct udk_eth_txconf {
    uint64_t offloads;

    uint64_t reserved_64s[2]; /* Reserved for future fields */
    void *reserved_ptrs[2];   /* Reserved for future fields */
};

struct udk_eth_xstat {
    uint64_t idx;        /* The index in xstats name array. */
    uint64_t value;     /* The statistic counter value. */
};

struct udk_eth_desc_lim {
    uint16_t nb_max;   /* Max allowed number of descriptors. */
    uint16_t nb_min;   /* Min allowed number of descriptors. */
    uint16_t nb_align; /* Number of descriptors should be aligned to. */
};

struct udk_eth_dev_portconf {
    uint16_t burst_size; /* Device-preferred burst size */
    uint16_t ring_size; /* Device-preferred size of queue rings */
    uint16_t nb_queues; /* Device-preferred number of queues */
};

struct udk_eth_dev_info {
    uint16_t min_mtu; /* Minimum MTU allowed */
    uint16_t max_mtu; /* Maximum MTU allowed */
    const uint32_t *dev_flags; /* Device flags */
    uint32_t min_rx_bufsize; /* Minimum size of RX buffer. */
    uint32_t max_rx_pktlen;  /* Maximum configurable length of RX pkt. */

    uint16_t max_rx_queues; /* Maximum number of RX queues. */
    uint16_t max_tx_queues; /* Maximum number of TX queues. */

    uint16_t max_vfs; /* Maximum number of VFs. */
    uint64_t rx_offload_capa; /* All RX offload capabilities including all per-queue ones */
    uint64_t tx_offload_capa; /* All TX offload capabilities including all per-queue ones */
    uint64_t rx_queue_offload_capa; /* Device per-queue RX offload capabilities. */
    uint64_t tx_queue_offload_capa; /* Device per-queue TX offload capabilities. */

    struct udk_eth_rxconf default_rxconf; /* Default RX configuration */
    struct udk_eth_txconf default_txconf; /* Default TX configuration */
    struct udk_eth_desc_lim rx_desc_lim;  /* RX descriptors limits */
    struct udk_eth_desc_lim tx_desc_lim;  /* TX descriptors limits */
    uint32_t speed_capa;  /* Supported speeds bitmap (ETH_LINK_SPEED_). */

    uint16_t nb_rx_queues; /* Configured Number of RX queues. */
    uint16_t nb_tx_queues; /* Configured Number of TX queues. */

    struct udk_eth_dev_portconf default_rxportconf; /* Rx parameter recommendations */
    struct udk_eth_dev_portconf default_txportconf; /* Tx parameter recommendations */

    uint64_t dev_capa; /* Generic device capabilities */

    uint64_t reserved_64s[2]; /* Reserved for future fields */
    void *reserved_ptrs[2];   /* Reserved for future fields */
};

struct udk_eth_dev;

typedef int  (*eth_dev_configure_t)(struct udk_eth_dev *dev);
typedef int  (*eth_dev_start_t)(struct udk_eth_dev *dev);
typedef void (*eth_dev_stop_t)(struct udk_eth_dev *dev);
typedef int  (*eth_dev_set_link_up_t)(struct udk_eth_dev *dev);
typedef int  (*eth_dev_set_link_down_t)(struct udk_eth_dev *dev);
typedef void (*eth_dev_close_t)(struct udk_eth_dev *dev);
typedef int (*eth_link_update_t)(struct udk_eth_dev *dev, int wait_to_complete);

typedef int (*eth_stats_get_t)(struct udk_eth_dev *dev, struct udk_eth_stats *igb_stats);
typedef int (*eth_stats_reset_t)(struct udk_eth_dev *dev);
typedef int (*eth_xstats_get_t)(struct udk_eth_dev *dev, struct udk_eth_xstat *stats, uint32_t n);
typedef int (*eth_xstats_reset_t)(struct udk_eth_dev *dev);
typedef int (*eth_xstats_get_names_t)(struct udk_eth_dev *dev, struct udk_eth_xstat_name *xstats_names, uint32_t size);

typedef int (*eth_dev_infos_get_t)(struct udk_eth_dev *dev, struct udk_eth_dev_info *dev_info);
typedef const uint32_t *(*eth_dev_supported_ptypes_get_t)(struct udk_eth_dev *dev);

typedef int (*eth_upcall_queue_setup_pre_t)(struct udk_eth_dev *dev, uint16_t queue_idx,
                                            uint16_t nb_desc, unsigned int socket_id);

typedef int (*eth_upcall_queue_setup_t)(struct udk_eth_dev *dev, uint16_t queue_idx,
                                        struct udk_mempool *mp);
typedef int (*eth_upcall_queue_release_t)(struct udk_eth_dev *dev, uint16_t queue_idx);
typedef int (*eth_rx_queue_setup_t)(struct udk_eth_dev *dev, uint16_t rx_queue_id, uint16_t nb_rx_desc,
                                    unsigned int socket_id, const struct udk_eth_rxconf *rx_conf,
                                    struct udk_mempool *mb_pool);
typedef int (*eth_tx_queue_setup_t)(struct udk_eth_dev *dev, uint16_t tx_queue_id, uint16_t nb_tx_desc,
                                    unsigned int socket_id, const struct udk_eth_txconf *tx_conf);
typedef void (*eth_queue_release_t)(void *queue);
typedef uint32_t (*eth_rx_queue_used_count_t)(struct udk_eth_dev *dev, uint16_t rx_queue_id);
typedef uint32_t (*eth_tx_queue_free_count_t)(struct udk_eth_dev *dev, uint16_t tx_queue_id);
typedef void (*eth_tx_done_cleanup_t)(struct udk_eth_dev *dev, uint16_t tx_queue_id);
typedef int (*eth_rx_descriptor_done_t)(void *rxq, uint16_t offset);
typedef int (*mtu_set_t)(struct udk_eth_dev *dev, uint16_t mtu);

struct udk_eth_dev_ops {
    eth_dev_configure_t        dev_configure; /* Configure device. */
    eth_dev_start_t            dev_start;     /* Start device. */
    eth_dev_stop_t             dev_stop;      /* Stop device. */
    eth_dev_set_link_up_t      dev_set_link_up;   /* Device link up. */
    eth_dev_set_link_down_t    dev_set_link_down; /* Device link down. */
    eth_dev_close_t            dev_close;     /* Close device. */
    eth_link_update_t          link_update;   /* Get device link state. */

    mtu_set_t                  mtu_set;       /* Set MTU. */

    eth_stats_get_t            stats_get;     /* Get generic device statistics. */
    eth_stats_reset_t          stats_reset;   /* Reset generic device statistics. */
    eth_xstats_get_t           xstats_get;    /* Get extended device statistics. */
    eth_xstats_reset_t         xstats_reset;  /* Reset extended device statistics. */
    eth_xstats_get_names_t     xstats_get_names; /* Get names of extended statistics. */

    eth_dev_infos_get_t        dev_infos_get; /* Get device info. */
    eth_dev_supported_ptypes_get_t dev_supported_ptypes_get; /* Get packet types supported and identified by device. */

    eth_upcall_queue_setup_pre_t upcall_queue_setup_pre;  /* Set up device upcall queue first step. */
    eth_upcall_queue_setup_t   upcall_queue_setup;  /* Set up device upcall queue second step. */
    eth_upcall_queue_release_t upcall_queue_release; /* Release upcall queue resource */
    eth_rx_queue_setup_t       rx_queue_setup;      /* Set up device RX queue. */
    eth_queue_release_t        rx_queue_release;    /* Release RX queue. */
    eth_rx_queue_used_count_t  rx_queue_used_count; /* Get the number of used RX descriptors. */
    eth_rx_descriptor_done_t   rx_descriptor_done;  /* Check rxd DD bit. */

    eth_tx_queue_setup_t       tx_queue_setup;      /* Set up device TX queue. */
    eth_queue_release_t        tx_queue_release;    /* Release TX queue. */
    eth_tx_queue_free_count_t  tx_queue_free_count; /* Get the number of free RX descriptors. */
    eth_tx_done_cleanup_t      tx_done_cleanup;     /* Cleanup txq done mbufs. */
};

struct udk_eth_dev {
    udk_eth_rx_burst_t rx_pkt_burst; /* Pointer to PMD receive function. */
    udk_eth_tx_burst_t tx_pkt_burst; /* Pointer to PMD transmit function. */
    struct udk_eth_dev_data *data;   /* Pointer to device data. */
    const struct udk_eth_dev_ops *dev_ops; /* Functions exported by PMD */
    struct udk_vdev_device *device; /* Backing device */
    enum udk_eth_dev_state state;   /* Flag indicating the port state */

    uint64_t reserved_64s[4]; /* Reserved for future fields */
    void *reserved_ptrs[4];   /* Reserved for future fields */
} udk_cache_aligned;

extern struct udk_eth_dev udk_eth_devices[UDK_MAX_ETHPORTS];
static inline uint16_t udk_eth_rx_burst(uint16_t port_id, uint16_t queue_id,
    struct udk_mbuf **rx_pkts, const uint16_t nb_pkts)
{
    struct udk_eth_dev *dev = &udk_eth_devices[port_id];

#ifdef UDK_ETHDEV_DEBUG
    if (!udk_eth_dev_is_valid_port(port_id)) {
        UDK_ETHDEV_LOG(ERR, "Invalid port_id=%u\n", port_id);
        return 0;
    }

    UDK_FUNC_PTR_OR_ERR_RET(*dev->rx_pkt_burst, 0);
#endif

    if (queue_id >= dev->data->nb_rx_queues) {
        UDK_ETHDEV_LOG(ERR, "Invalid RX queue_id=%u\n", queue_id);
        return 0;
    }

    return (*dev->rx_pkt_burst)(dev->data->rx_queues[queue_id], rx_pkts, nb_pkts);
}

static inline uint16_t udk_eth_tx_burst(uint16_t port_id, uint16_t queue_id,
    struct udk_mbuf **tx_pkts, uint16_t nb_pkts)
{
    struct udk_eth_dev *dev = &udk_eth_devices[port_id];

#ifdef UDK_ETHDEV_DEBUG
    if (!udk_eth_dev_is_valid_port(port_id)) {
        UDK_ETHDEV_LOG(ERR, "Invalid port_id=%u\n", port_id);
        return 0;
    }
    UDK_FUNC_PTR_OR_ERR_RET(*dev->tx_pkt_burst, 0);

    if (queue_id >= dev->data->nb_tx_queues) {
        UDK_ETHDEV_LOG(ERR, "Invalid TX queue_id=%u\n", queue_id);
        return 0;
    }
#endif

    return (*dev->tx_pkt_burst)(dev->data->tx_queues[queue_id], tx_pkts, nb_pkts);
}

struct udk_eth_dev *udk_eth_dev_allocate(const char *name);
struct udk_eth_dev *udk_eth_dev_allocated(const char *name);
void udk_eth_dev_probing_finish(struct udk_eth_dev *dev);
int udk_eth_dev_socket_id(uint16_t port_id);
int udk_eth_dev_is_valid_port(uint16_t port_id);
int udk_eth_macaddr_get(uint16_t port_id, struct udk_ether_addr *mac_addr);
int udk_eth_dev_get_port_by_name(const char *name, uint16_t *port_id);

int udk_eth_dev_info_get(uint16_t port_id, struct udk_eth_dev_info *dev_info);
int udk_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q, const struct udk_eth_conf *dev_conf);
int udk_eth_dev_start(uint16_t port_id);
void udk_eth_dev_close(uint16_t port_id);

int udk_eth_upcall_queue_setup_pre(uint16_t port_id, uint16_t rx_queue_id, uint16_t nb_rx_desc, unsigned int socket_id);
int udk_eth_upcall_queue_setup(uint16_t port_id, uint16_t rx_queue_id, struct udk_mempool *mp);
int udk_eth_upcall_queue_release(uint16_t port_id, uint16_t rx_queue_id);
int udk_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, uint16_t nb_rx_desc, unsigned int socket_id,
    const struct udk_eth_rxconf *rx_conf, struct udk_mempool *mp);
int udk_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id, uint16_t nb_tx_desc, unsigned int socket_id,
    const struct udk_eth_txconf *tx_conf);
uint32_t udk_eth_tx_queue_free_count_get(uint16_t port_id, uint16_t queue_id);
void udk_eth_tx_done_cleanup(uint16_t port_id, uint16_t queue_id);
int udk_eth_xstats_get_names(uint16_t port_id, struct udk_eth_xstat_name *xstats_names, unsigned int size);
int udk_eth_xstats_get(uint16_t port_id, struct udk_eth_xstat *xstats, uint32_t n);
int udk_dev_remove(struct udk_vdev_device *dev);
int udk_eth_dev_release_port(struct udk_eth_dev *eth_dev);
void udk_eth_dev_stop(uint16_t port_id);
#ifdef __cplusplus
}
#endif

#endif